// // <copyright file=StorageAnalyticsExtension.cs company="Microsoft">
// //
// //  This source is subject to the Microsoft Public License (Ms-PL).
// //  Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// //  All other rights reserved.
// // </copyright>

namespace XRay.Library.StorageAnalyticsExtension
{
    #region

    using System;
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.Text;
    using Contracts;
    using Microsoft.WindowsAzure;
    using Microsoft.WindowsAzure.StorageClient;

    #endregion

    public enum AuthorizationType
    {
        SharedKey = 0,

        SharedKeyLite = 1
    }

    public static class StorageAnalyticsExtension
    {
        public const string DefaultVersionHeaderName = "x-ms-version";
        public const string RequestIdHeaderName = "x-ms-request-id";
        public const string DefaultVersionHeaderContent = "2009-09-19";
        public const int DefaultTimeoutInSecs = 30;

        public static void SetStorageServiceProperties(this CloudBlobClient client, StorageServiceProperties properties)
        {
            SetServiceProperties(client.BaseUri, client.Credentials, properties, AuthorizationType.SharedKey);
        }

        public static void SetStorageServiceProperties(
            this CloudQueueClient client, Uri queueUri, StorageServiceProperties properties)
        {
            SetServiceProperties(queueUri, client.Credentials, properties, AuthorizationType.SharedKey);
        }

        public static void SetStorageServiceProperties(this CloudTableClient client, StorageServiceProperties properties)
        {
            SetServiceProperties(client.BaseUri, client.Credentials, properties, AuthorizationType.SharedKeyLite);
        }

        public static StorageServiceProperties GetStorageServiceProperties(this CloudBlobClient client)
        {
            return GetStorageServiceProperties(client.BaseUri, client.Credentials, AuthorizationType.SharedKey);
        }

        public static StorageServiceProperties GetStorageServiceProperties(this CloudQueueClient client, Uri queueUri)
        {
            return GetStorageServiceProperties(queueUri, client.Credentials, AuthorizationType.SharedKey);
        }

        public static StorageServiceProperties GetStorageServiceProperties(this CloudTableClient client)
        {
            return GetStorageServiceProperties(client.BaseUri, client.Credentials, AuthorizationType.SharedKeyLite);
        }

        private static StorageServiceProperties GetStorageServiceProperties(
            Uri baseUri, StorageCredentials credentials, AuthorizationType authorizationType)
        {
            var uriBuilder = new UriBuilder(baseUri)
                                 {
                                     Query = string.Format(
                                         CultureInfo.InvariantCulture,
                                         "comp=properties&restype=service&timeout={0}",
                                         DefaultTimeoutInSecs)
                                 };

            var httpRequest = (HttpWebRequest)WebRequest.Create(uriBuilder.Uri);
            httpRequest.Headers.Add(DefaultVersionHeaderName, DefaultVersionHeaderContent);
            httpRequest.Method = "GET";

            if (authorizationType == AuthorizationType.SharedKeyLite)
            {
                credentials.SignRequestLite(httpRequest);
            }
            else
            {
                credentials.SignRequest(httpRequest);
            }

            using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse())
            {
                if (httpResponse.StatusCode != HttpStatusCode.OK)
                {
                    throw new ProtocolException("Request failed", new WebFaultException(httpResponse.StatusCode));
                }

                using (var responseStream = httpResponse.GetResponseStream())
                {
                    if (responseStream == null)
                    {
                        throw new NullReferenceException("Response stream is null");
                    }

                    using (var reader = new StreamReader(responseStream))
                    {
                        return StorageServiceProperties.Convert(reader.ReadToEnd());
                    }
                }
            }
        }

        private static void SetServiceProperties(
            Uri baseUri,
            StorageCredentials credentials,
            StorageServiceProperties properties,
            AuthorizationType authorizationType)
        {
            var uriBuilder = new UriBuilder(baseUri)
                                 {
                                     Query = string.Format(
                                         CultureInfo.InvariantCulture,
                                         "comp=properties&restype=service&timeout={0}",
                                         DefaultTimeoutInSecs)
                                 };

            var httpRequest = (HttpWebRequest)WebRequest.Create(uriBuilder.Uri);
            httpRequest.Headers.Add(DefaultVersionHeaderName, DefaultVersionHeaderContent);
            httpRequest.Method = "PUT";

            var requestStr = StorageServiceProperties.Convert(properties);
            httpRequest.ContentLength = requestStr.Length;

            if (authorizationType == AuthorizationType.SharedKeyLite)
            {
                credentials.SignRequestLite(httpRequest);
            }
            else
            {
                credentials.SignRequest(httpRequest);
            }

            using (var requestStream = httpRequest.GetRequestStream())
            {
                requestStream.Write(Encoding.UTF8.GetBytes(requestStr), 0, requestStr.Length);
            }

            using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse())
            {
                if (httpResponse.StatusCode != HttpStatusCode.Accepted)
                {
                    throw new ProtocolException("Request failed", new WebFaultException(httpResponse.StatusCode));
                }
            }
        }
    }
}